package org.springblade.thingsphere.manage.service.impl;

import cn.hutool.cache.Cache;
import cn.hutool.cache.CacheUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.oss.model.BladeFile;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springblade.thingsphere.CompositeProtocolSupport;
import org.springblade.thingsphere.manage.conf.ThingsphereConfig;
import org.springblade.thingsphere.manage.excel.ProtocolExcel;
import org.springblade.thingsphere.manage.mapper.ProtocolMapper;
import org.springblade.thingsphere.manage.pojo.entity.ProtocolEntity;
import org.springblade.thingsphere.manage.pojo.vo.ProtocolVO;
import org.springblade.thingsphere.manage.service.IProtocolService;
import org.springblade.thingsphere.network.protocol.ProtocolSupportDefinition;
import org.springblade.thingsphere.network.protocol.impl.ProtocolAssetSupplier;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date;
import java.util.List;

/**
 * 协议管理 服务实现类
 *
 * @author lhb
 * @since 2024-09-26
 */
@Service
@AllArgsConstructor
public class ProtocolServiceImpl extends BaseServiceImpl<ProtocolMapper, ProtocolEntity> implements IProtocolService {

	private final ThingsphereConfig thingsphereConfig;
	private final ProtocolAssetSupplier protocolAssetSupplier;

	@Override
	public IPage<ProtocolVO> selectProtocolPage(IPage<ProtocolVO> page, ProtocolVO protocol) {
		return page.setRecords(baseMapper.selectProtocolPage(page, protocol));
	}


	@Override
	public List<ProtocolExcel> exportProtocol(Wrapper<ProtocolEntity> queryWrapper) {
		List<ProtocolExcel> protocolList = baseMapper.exportProtocol(queryWrapper);
		//protocolList.forEach(protocol -> {
		//	protocol.setTypeName(DictCache.getValue(DictEnum.YES_NO, Protocol.getType()));
		//});
		return protocolList;
	}

	@Override
	public BladeFile putFile(MultipartFile file) {

		if (file.isEmpty()) {
			throw new ServiceException("文件内容不存在");
		}
		try {
			// 创建目录（如果不存在）
			Path uploadPath = Paths.get(thingsphereConfig.getProtocol().getLocalPath());
			if (!Files.exists(uploadPath)) {
				Files.createDirectories(uploadPath);
			}

			// 保存文件
			String originalFilename = file.getOriginalFilename();
			int lastDotIndex = originalFilename.lastIndexOf(".");
			if (lastDotIndex == -1) {
				throw new ServiceException("文件格式不正确");
			}
			String suffix = originalFilename.substring(lastDotIndex + 1).toLowerCase();
			if (!"jar".equals(suffix)) {
				throw new ServiceException("文件格式不正确,请上传jar文件");
			}
			String fileName = IdUtil.fastSimpleUUID() + "." + suffix;
			String filePath = thingsphereConfig.getProtocol().getLocalPath() + fileName;
			Path path = Paths.get(filePath);
			Files.write(path, file.getBytes());
			BladeFile bladeFile = new BladeFile();
			bladeFile.setLink(filePath);
			bladeFile.setName(fileName);
			bladeFile.setOriginalName(originalFilename);
			return bladeFile;
		} catch (Exception e) {
			throw new ServiceException("系统错误,上传失败");
		}
	}

	@Override
	public R<Boolean> publish(ProtocolEntity protocol) {

		ProtocolEntity protocolEntity = this.getById(protocol.getId());
		if (null == protocolEntity) {
			throw new ServiceException("协议不存在");
		}
		if (1 == protocolEntity.getStatus()) {
			throw new ServiceException("协议已发布");
		}

		// 加载jar到虚拟机
		ProtocolSupportDefinition definition = new ProtocolSupportDefinition();
		definition.setId(protocolEntity.getId());
		definition.setName(protocolEntity.getName());
		definition.setDescription(protocolEntity.getDescription());
		definition.setClazzName(protocolEntity.getClazzName());
		definition.setJarPath(protocolEntity.getJarPath());
		CompositeProtocolSupport compositeProtocolSupport = protocolAssetSupplier.load(definition);
		if (null == compositeProtocolSupport) {
			protocolEntity.setStatus(2);
		} else {
			protocolEntity.setStatus(1);
		}
		protocolEntity.setUpdateTime(new Date());
		protocolEntity.setUpdateUser(AuthUtil.getUserId());
		this.updateById(protocolEntity);

		if (2 == protocolEntity.getStatus()) {
			return R.fail("发布协议失败");
		}
		return R.data(true);
	}

	@Override
	public R<Boolean> unpublish(ProtocolEntity protocol) {
		ProtocolEntity protocolEntity = this.getById(protocol.getId());
		if (null == protocolEntity) {
			throw new ServiceException("协议不存在");
		}
		if (1 != protocolEntity.getStatus()) {
			throw new ServiceException("协议未发布");
		}
		ProtocolSupportDefinition definition = new ProtocolSupportDefinition();
		definition.setId(protocolEntity.getId());
		definition.setName(protocolEntity.getName());
		definition.setDescription(protocolEntity.getDescription());
		definition.setClazzName(protocolEntity.getClazzName());
		definition.setJarPath(protocolEntity.getJarPath());
		protocolAssetSupplier.unLoadJar(definition);

		protocolEntity.setStatus(0);
		protocolEntity.setUpdateTime(new Date());
		protocolEntity.setUpdateUser(AuthUtil.getUserId());
		return R.data(this.updateById(protocolEntity));
	}

	private static final String CACHE_NAME = "iot:protocol";
	private static final Cache<String, List<ProtocolEntity>> fifoCache = CacheUtil.newFIFOCache(1000);

	@Override
	public boolean dictClear() {
		fifoCache.clear();
		return true;
	}

	@Override
	public List<ProtocolEntity> dictList() {
		if (fifoCache.containsKey(CACHE_NAME)) {
			return fifoCache.get(CACHE_NAME);
		}

		List<ProtocolEntity> list = this.list(Wrappers.<ProtocolEntity>lambdaQuery().eq(ProtocolEntity::getStatus, 1));
		fifoCache.put(CACHE_NAME, list);
		return list;
	}

}
